#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "Bitmap.h"


int* YUY2ToRGB(unsigned char* src, int width, int height);

struct RGB {
	unsigned char r;
	unsigned char g;
	unsigned char b;
};

struct RGB yuvTorgb(int pY, int pU, int pV)
{
	struct RGB rgb;

	int R, G, B;

	R = (int)(pY + 1.732446 * (pU - 128));
	G = (int)(pY - 0.698001 * (pU - 128) - 0.703125 * (pV - 128));
	B = (int)(pY + 1.370705 * (pV - 128));

	
	if(R > 255) R = 255;
	if(G > 255) G = 255;
	if(B > 255) B = 255;
	if(R < 0) R = 0;
	if(G < 0) G = 0;
	if(B < 0) B = 0;

	rgb.r = R;
	rgb.g = G;
	rgb.b = B;

	return rgb;
}


int main(int argc, char** argv)
{
	if(argc != 3) {
		printf("yuv2bmp input.yuv output.bmp\n");
		return 0;
	}
	BitmapHeader bitmapHeader;
	// bitmap file header
	*((unsigned char*)&bitmapHeader.file_header.bfType+0) = 'B'; // bitmap 文件标志
	*((unsigned char*)&bitmapHeader.file_header.bfType+1) = 'M';
	*((unsigned int*)&bitmapHeader.file_header.bfSize+0) = 640 * 480 * 3 + 54;  // 整个文件大小
	*((unsigned short*)&bitmapHeader.file_header.bfReserved1) = 0;  // researve 0
	*((unsigned short*)&bitmapHeader.file_header.bfReserved2) = 0;  // researve 0
	*((unsigned int*)&bitmapHeader.file_header.bfOffBits) = 54;  // rgb数据在文件的偏移量
	// bitmap info header
	*((unsigned int*)&bitmapHeader.info_header.biSize) = 40;  // InfoHeader大小
	*((unsigned int*)&bitmapHeader.info_header.biWidth) = 640;  // 文件宽度
	*((unsigned int*)&bitmapHeader.info_header.biHeight) = 480;  // 文件高度
	*((unsigned short*)&bitmapHeader.info_header.biPlanes) = 1;
	*((unsigned short*)&bitmapHeader.info_header.biBitsPerPixel) = 24; // 每个像素字节数
	*((unsigned int*)&bitmapHeader.info_header.biCompression) = 0;  // 压缩等级
	*((unsigned int*)&bitmapHeader.info_header.biImageSize) = 640 * 480 * 3;  //数据大小=文件大小-文件头 
	*((unsigned int*)&bitmapHeader.info_header.biXPixelsPerMeter) = 0;
	*((unsigned int*)&bitmapHeader.info_header.biYPixelsPerMeter) = 0;
	*((unsigned int*)&bitmapHeader.info_header.biClrUsed) = 0;
	*((unsigned int*)&bitmapHeader.info_header.biClrImportant) = 0;

	//printf("buid a bitmapHeader with size %d\n", sizeof(BitmapHeader));
	

	// now only convert 640 * 480
	int yuvFd = open(argv[1], O_RDWR);
	if(-1 == yuvFd) {
		perror("open yuv input");
		return -1;
	}
	unsigned char yuvBuf[0x96000];
	int n = 0;
	if(0x96000 != (n = read(yuvFd, yuvBuf, 0x96000))) {
		perror("Error in read yuv files");
		return -1;
	}
	printf("read yuv size 0x%x\n", n);

	int* rgbBuf = YUY2ToRGB(yuvBuf, 640, 480);

	// create a file
	//int bitmapFd = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
	int bitmapFd = open(argv[2], O_WRONLY | O_CREAT);
	if(-1 == bitmapFd) {
		perror("Open output.bmp");
	}
	if(sizeof(bitmapHeader) != write(bitmapFd, &bitmapHeader, sizeof(bitmapHeader))) {
		perror("Write bitmap header");
	}

	int rgbDataLen = 640 * 480 * 3;

	if(rgbDataLen != write(bitmapFd, rgbBuf, rgbDataLen)) {
		perror("Write bitmap data");
	}

	close(yuvFd);
	close(bitmapFd);

	return 0;

}


int* YUY2ToRGB(unsigned char* src, int width, int height) {  
	int numOfPixel = width * height;  
	int* rgbI = malloc(numOfPixel * 3);  
	unsigned char* rgbC = (unsigned char*)rgbI;  
	memset(rgbC, 0, numOfPixel*3);

	int i = 0;
	int index = 0;


	for(i = 0; i < numOfPixel * 2; i += 4) {
		int Y1 = i;  
		int Y2 = Y1+2;  
		int U = Y1+1;  
		int V = Y1+3;  
		//int index = (Y1>>1)*3;  
		struct RGB tmp = yuvTorgb(src[Y1], src[U], src[V]);  
		// find one rgb pixel
		rgbC[index+0] = tmp.r;  
		rgbC[index+1] = tmp.g;  
		rgbC[index+2] = tmp.b;  
		index += 3;  

		//find another rgb pixel
		tmp = yuvTorgb(src[Y2], src[U], src[V]);  
		rgbC[index+0] = tmp.r;  
		rgbC[index+1] = tmp.g;  
		rgbC[index+2] = tmp.b;  
		index += 3;
	}
	return rgbI;  
} 
/*
   static int[] YUY2ToRGB(byte[] src, int width, int height){  
   int numOfPixel = width * height;  
   int[] rgb = new int[numOfPixel*3];  
   int lineWidth = 2*width;  
   for(int i=0; i<height; i++){  
   int startY = i*lineWidth;  
   for(int j = 0; j < lineWidth; j+=4){  
   int Y1 = j + startY;  
   int Y2 = Y1+2;  
   int U = Y1+1;  
   int V = Y1+3;  
   int index = (Y1>>1)*3;  
   RGB tmp = yuvTorgb(src[Y1], src[U], src[V]);  
   rgb[index+R] = tmp.r;  
   rgb[index+G] = tmp.g;  
   rgb[index+B] = tmp.b;  
   index += 3;  
   tmp = yuvTorgb(src[Y2], src[U], src[V]);  
   rgb[index+R] = tmp.r;  
   rgb[index+G] = tmp.g;  
   rgb[index+B] = tmp.b;  
   }  
   }  
   return rgb;  
   } 
   */
